export default class CoordinateToWebgl {
  polygon(coordinates) {
    //rotational===true anticlockwise otherwise is clockwise
    const pointsInTriangle = (point1, point2, point3, rotational = true, data) => {
      let [ab, bc, ca] = [
        [point2.x - point1.x, point2.y - point1.y],
        [point3.x - point2.x, point3.y - point2.y],
        [point1.x - point3.x, point1.y - point3.y]
      ];
      // let pointInTriangleFlag = true;
      for (let i = 0, length = data.length; i < length; i++) {
        let p = data[i];
        if (p !== point1 && p !== point2 && p !== point3 && !p.done) {
          let [ap, bp, cp] = [
            [p.x - point1.x, p.y - point1.y],
            [p.x - point2.x, p.y - point2.y],
            [p.x - point3.x, p.y - point3.y]
          ]

          let z1 = ab[0] * ap[1] - ab[1] * ap[0];
          let z2 = bc[0] * bp[1] - bc[1] * bp[0];
          let z3 = ca[0] * cp[1] - ca[1] * cp[0];
          if (z1 > 0 && z2 > 0 && z3 > 0 || z1 < 0 && z2 < 0 && z3 < 0) {
            return true;
          }
        }
      }
      return false;
    }

    //orientation===false anticlockwise   return true is ear point ,false maybe concave or some points in the triangle
    const judgePoint = (point, data, orientation = false) => {
      let previous = data[point.previous];
      let next = data[point.next];

      let ap = [point.x - previous.x, point.y - previous.y];
      let pb = [next.x - point.x, next.y - point.y];

      if (ap[0] * pb[1] - ap[1] * pb[0] < 0) {
        point.isConcave = true;
        point.isEar = false;
        return false;
      }
      if (!pointsInTriangle(previous, point, next, true, data)) {
        point.isEar = true;
        return true;
      }
      return false;
    }

    const getPoints = data => {
      let earPoints = [];
      let concavePoints = [];
      for (let i = 0, length = data.length; i < length; i += 1) {
        if (data[i].done) continue;
        let flag = judgePoint(data[i], data);
        if (flag) {
          earPoints.push(data[i]);
        } else {
          if (data[i].isConcave) {
            concavePoints.push(data[i]);
          }
        }
      }
      return {
        earPoints,
        concavePoints,
      }
    }

    const isObjInArray = (obj, array) => {
      let arr = array.filter(value => value === obj);
      if (arr.length > 0) return true;
      return false;
    }

    const getOnePolygonData = (polygonData, offsetIndex = 0) => {
      let formatData = [];
      for (let i = 0, length = polygonData.length; i < length; i = i + 2) {
        formatData.push({
          previous: ((i - 2 + length) / 2) % (length / 2),
          next: ((i + 2) / 2) % (length / 2),
          isEar: false,
          index: i / 2,
          isConcave: false,
          x: polygonData[i],
          y: polygonData[i + 1],
          done: false, //done===true means the points is not in the polygon data.
        })
      }
      let points = getPoints(formatData);
      let dataIndex = [];
      let earPoints = points.earPoints;
      while (earPoints.length > 0) {
        let point = earPoints.shift();
        if (point.done) continue;
        point.done = true;
        dataIndex.push(point.previous + offsetIndex, point.index + offsetIndex, point.next + offsetIndex);

        let previous = formatData[point.previous];
        let next = formatData[point.next];

        previous.next = next.index;
        next.previous = previous.index;
        judgePoint(previous, formatData);
        if (previous.isEar) {
          if (!isObjInArray(previous, earPoints)) {
            earPoints.push(previous);
          }
        } else {
          earPoints = earPoints.filter(value => value !== previous);
        }
        judgePoint(next, formatData);
        if (next.isEar) {
          if (!isObjInArray(next, earPoints)) {
            earPoints.push(next);
          }
        } else {
          earPoints = earPoints.filter(value => value !== next);
        }
      }

      return {
        polygonData,
        dataIndex
      }
    }

    let data = [];
    if (Array.isArray(coordinates) && coordinates.length > 0) {
      let pointData = [];
      let dataIndex = [];
      let offset = 0;
      for (let i = 0, length = coordinates.length; i < length; i++) {
        let obj = getOnePolygonData(coordinates[i], offset);
        offset += obj.polygonData.length / 2;
        pointData = pointData.concat(obj.polygonData);
        dataIndex = dataIndex.concat(obj.dataIndex);
        if (pointData.length > 5000 || dataIndex.length > 5000) {
          data.push({
            pointData,
            dataIndex
          })
          pointData = [];
          dataIndex = [];
        }
      }

      data.push({
        pointData,
        dataIndex
      })
    }
    return data;
  }
}